﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.IO;
using System.Reflection;
using System.Security;
using System.Xml;
using System.Xml.XPath;
using System.Windows.Forms;
using System.Security.AccessControl;
using System.Security.Permissions;

namespace TeamReview.SetupRegistrationAction
{
    [RunInstaller(true)]
    public class InstallerTeamReview : Installer
    {
        private const string AddinName = @"TeamReview.VSNetAddIn.Addin";
        private const string DestAddinName = @"TeamReview2010.VSNetAddIn.Addin";

        public override void Install(IDictionary stateSaver)
        {

            
            base.Install(stateSaver);
           
            Assembly asm = Assembly.GetExecutingAssembly();

            // get directory name of install directory
           
            string fileName = Path.Combine(Path.GetDirectoryName(asm.Location), AddinName);
            FileInfo fInfo = new FileInfo(fileName);
            FileSecurity security = fInfo.GetAccessControl();
            FileSystemAccessRule rule = new FileSystemAccessRule(Environment.UserName, FileSystemRights.FullControl, AccessControlType.Allow);
            security.SetAccessRule(rule);
            File.SetAccessControl(fInfo.FullName, security);                
    

            if (fInfo.Exists == false)
            {
                throw new FileNotFoundException(
                  string.Format("File '{0}' is not found. Installation will be aborted or not complete.", fileName));
           }

            try
            {
                // Load the .Addin file into XML document
                XmlDocument doc = new XmlDocument();
                doc.Load(fInfo.FullName);
                XPathNavigator navigator = doc.CreateNavigator();
                XmlNamespaceManager nsmgr = new XmlNamespaceManager(navigator.NameTable);
                nsmgr.AddNamespace("ae", "http://schemas.microsoft.com/AutomationExtensibility");

                XmlElement root = doc.DocumentElement;
                if (root == null) throw new XmlSyntaxException("Addin XML Root element definition");

                XmlNode assemblyNode = root.SelectSingleNode("/ae:Extensibility/ae:Addin/ae:Assembly", nsmgr);
                if (assemblyNode == null)
                {
                    throw new XmlSyntaxException(
                      "XML File is missing the Assembly Element, installation is not complete");
                }

                assemblyNode.InnerText = Path.ChangeExtension(fileName, "dll");

                // Save the updated xml in the destination .addin File
                string source = AddinFolderPath();
                DirectoryInfo sourceInfo = new DirectoryInfo(source);
                DirectorySecurity directorySecurity = Directory.GetAccessControl(source);

                FileSystemAccessRule accessRule = new FileSystemAccessRule(@"BUILTIN\Users", FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly, AccessControlType.Allow);
                bool modified = false; 
                directorySecurity.ModifyAccessRule(AccessControlModification.Add, accessRule, out modified);
                if (modified) { 
                    sourceInfo.Create(directorySecurity);
                }
                else
                { 
                    sourceInfo.Create(); 
                }
                string destFile = Path.Combine(source, DestAddinName);                
                doc.Save(destFile);
            }
            catch (Exception ex)
            {
                throw new Exception(
                  string.Format(
                    "Failure to process file '{0}'. Error= {1}. Installation will be aborted or not complete.",
                    fInfo.FullName, ex), ex);
            }
        }

        /// <summary>
        /// ["ALLUSERS"] is passed via the customactiondata in the setup project
        /// if ["ALLUSERS"] is not set or ="2", do a per user install
        /// see http://msdn.microsoft.com/en-us/library/aa367559(VS.85).aspx
        /// </summary>
        /// <returns>
        /// Path to C:\Documents and Settings\<user>\Application Data\Microsoft\MSEnvShared\Addins
        /// </returns>
        private string AddinFolderPath()
        {
            string alluser = this.Context.Parameters["ALLUSERS"];
            string folder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
            if (string.IsNullOrEmpty(alluser) || (string.Compare(alluser, "2") == 0))
            {
                folder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
              
            }

            DirectoryInfo sourceInfo = new DirectoryInfo(folder);
            DirectorySecurity directorySecurity = Directory.GetAccessControl(folder);

            FileSystemAccessRule accessRule = new FileSystemAccessRule(@"BUILTIN\Users", FileSystemRights.FullControl, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly, AccessControlType.Allow);
            bool modified = false;
            directorySecurity.ModifyAccessRule(AccessControlModification.Add, accessRule, out modified);


            return string.Concat(folder, @"\Microsoft\MSEnvShared\Addins");
        }

        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);

            try
            {
                string folderPath = AddinFolderPath();
                DirectoryInfo dirInfo = new DirectoryInfo(folderPath);
                if (dirInfo.Exists)
                {
                    string destFile = Path.Combine(folderPath, DestAddinName);
                    File.Delete(destFile);

                    File.Delete(Path.Combine(folderPath, @"TeamReview.config"));
                    File.Delete(Path.Combine(folderPath, @"TeamReview.log"));
                }
            }
            catch
            {
            }
        }
    }
}
